package com.cenxi.manage;

import cn.hutool.crypto.digest.MD5;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.cenxi.common.util.MenuUtils;
import com.cenxi.common.convert.AccountDTOTOAccountEntity;
import com.cenxi.common.convert.RoleDTOTORoleEntity;
import com.cenxi.common.dto.req.AccountReqDTO;
import com.cenxi.common.dto.resp.AccountRespDTO;
import com.cenxi.common.dto.resp.LoginAccountRespDTO;
import com.cenxi.common.dto.resp.RoleRespDTO;
import com.cenxi.common.exceptions.ServiceException;
import com.cenxi.common.util.JwtUtils;
import com.cenxi.common.util.SecurityUtils;
import com.cenxi.common.util.req.PageReq;
import com.cenxi.common.util.req.Req;
import com.cenxi.common.util.resp.PageResp;
import com.cenxi.common.util.resp.Resp;
import com.cenxi.dao.domain.*;
import com.cenxi.dao.mapper.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @Author cenxi
 * @Date 2023/8/16 11:49
 * @Version 1.0
 */
@Slf4j
@Component
public class ManageAccountService {
    @Autowired
    private AccountMapper accountMapper;
    @Autowired
    private AccountRoleMapper accountRoleMapper;
    @Autowired
    private RoleMapper roleMapper;
    @Autowired
    private RoleMenuMapper roleMenuMapper;
    @Autowired
    private MenuMapper menuMapper;

    public PageResp<AccountRespDTO> page(PageReq<AccountReqDTO> req) {
        AccountReqDTO data = req.getData();
        LambdaQueryWrapper<Account> lqw = new LambdaQueryWrapper<>();
        lqw.eq(Account::getDeleted, 1)
                .eq(Objects.nonNull(data.getState()), Account::getState, data.getState())
                .like(StringUtils.isNotBlank(data.getAccount()), Account::getAccount, data.getAccount());
        if (!CollectionUtils.isEmpty(data.getRoles())) {
            for (RoleRespDTO role : data.getRoles()) {
                lqw.in(Account::getId, accountRoleMapper.selectList(new LambdaQueryWrapper<AccountRole>()
                                .eq(AccountRole::getRoleId, role.getRoleId())).stream()
                        .map(AccountRole::getAccountId).collect(Collectors.toList()));
            }
        }
        Page<Account> accountPage = accountMapper.selectPage(new Page<>(req.getPageIndex(), req.getPageSize()), lqw);
        return PageResp.succeed(accountPage.getPages(), accountPage.getTotal(),
                accountPage.hasNext(), AccountDTOTOAccountEntity.INSTANCE.entity2dto(accountPage.getRecords()));
    }

    @Transactional(rollbackFor = Exception.class)
    public Resp<Boolean> create(Req<AccountReqDTO> req) {
        // 新增账号
        Account plateAccountEntity = AccountDTOTOAccountEntity.INSTANCE.accountReqToAccount(req.getData());
        if (!plateAccountEntity.getAccount().matches("\\w{1,20}") || !plateAccountEntity.getPassword().matches("\\w{1,20}")) {
            return Resp.error("账号或密码格式不对");
        }
        if (plateAccountEntity.getState() < 0 || plateAccountEntity.getState() > 1) {
            return Resp.error("账号状态有误");
        }
        // 检验账户是否已存在
        if (accountMapper.exists(new LambdaQueryWrapper<Account>()
                .eq(Account::getAccount, plateAccountEntity.getAccount())
                .eq(Account::getDeleted, 1))) {
            return Resp.error("账户已存在");
        }
        // 加密 密码
        plateAccountEntity.setPassword(new MD5().digestHex16(plateAccountEntity.getPassword()));
        if (accountMapper.insert(plateAccountEntity) > 0) {
            // 添加角色
            if (!CollectionUtils.isEmpty(req.getData().getRoles())) {
                for (RoleRespDTO role : req.getData().getRoles()) {
                    // 查看角色是否存在
                    if (Objects.isNull(roleMapper.selectById(role.getRoleId()))) {
                        throw new ServiceException("角色不存在");
                    }
                    AccountRole accountRole = new AccountRole();
                    accountRole.setAccountId(plateAccountEntity.getId());
                    accountRole.setRoleId(Long.valueOf(role.getRoleId()));
                    accountRoleMapper.insert(accountRole);
                }
            }
            return Resp.succeed(true);
        }
        return Resp.succeed(false);
    }

    public Resp<AccountRespDTO> findById(String data) {
        return Resp.succeed(AccountDTOTOAccountEntity.INSTANCE.entity2dto(accountMapper.selectById(data)));
    }

    @Transactional(rollbackFor = Exception.class)
    public Resp<Boolean> edit(Req<AccountReqDTO> req) {
        AccountReqDTO data = req.getData();
        // 新增账号
        Account plateAccountEntity = AccountDTOTOAccountEntity.INSTANCE.accountReqToAccount(data);
        LambdaQueryWrapper<Account> lqw = new LambdaQueryWrapper<>();
        Account account = new Account();
        if (accountMapper.exists(new LambdaQueryWrapper<Account>()
                .eq(Account::getAccount, plateAccountEntity.getAccount())
                .eq(Account::getDeleted, 1))) {
            return Resp.error("账户已存在");
        }
        account.setAccount(plateAccountEntity.getAccount());
        account.setState(plateAccountEntity.getState());
        account.setRemark(plateAccountEntity.getRemark());
        if (accountMapper.update(account, lqw) > 0) {
            // 修改角色/ 先删后加
            if (!CollectionUtils.isEmpty(data.getRoles())) {
                accountRoleMapper.delete(new LambdaQueryWrapper<AccountRole>()
                        .eq(AccountRole::getAccountId, plateAccountEntity.getId()));
                for (RoleRespDTO role : data.getRoles()) {
                    // 查看角色是否存在
                    if (Objects.isNull(roleMapper.selectById(role.getRoleId()))) {
                        throw new ServiceException("角色不存在");
                    }
                    AccountRole accountRole = new AccountRole();
                    accountRole.setAccountId(plateAccountEntity.getId());
                    accountRole.setRoleId(Long.valueOf(role.getRoleId()));
                    accountRoleMapper.insert(accountRole);
                }
            }
            return Resp.succeed(true);
        }
        return Resp.succeed(false);
    }

    public Resp<Boolean> enable(String data, byte enable) {
        Account account = accountMapper.selectById(data);
        if (Objects.isNull(account)) {
            return Resp.error("账号不存在");
        }
        Account acc = new Account();
        acc.setId(account.getId());
        acc.setState((int) enable);
        return Resp.succeed(accountMapper.updateById(acc) > 0);
    }

    public Resp<Boolean> disable(String data, byte disable) {
        Account account = accountMapper.selectById(data);
        if (Objects.isNull(account)) {
            return Resp.error("账号不存在");
        }
        Account acc = new Account();
        acc.setId(account.getId());
        acc.setState((int) disable);
        return Resp.succeed(accountMapper.updateById(acc) > 0);
    }

    @Transactional(rollbackFor = Exception.class)
    public Resp<Boolean> deleteById(String data) {
        if (accountMapper.deleteById(data) > 0) {
            // 删除账户绑定角色相关信息
            LambdaQueryWrapper<AccountRole> lqw = new LambdaQueryWrapper<>();
            lqw.eq(AccountRole::getAccountId, data);
            accountRoleMapper.delete(lqw);
            return Resp.succeed(true);
        }
        return Resp.succeed(false);
    }

    public Resp<LoginAccountRespDTO> getLoginAccount() {
        String userId = JwtUtils.getUserId(SecurityUtils.getToken());
        if (StringUtils.isBlank(userId)) {
            return Resp.error("登录账户信息不存在，请重新登录");
        }
        LoginAccountRespDTO loginAccountRespDTO = new LoginAccountRespDTO();
        loginAccountRespDTO.setAccount(AccountDTOTOAccountEntity.INSTANCE.entity2dto(accountMapper.selectById(userId)));
        List<Long> collect = accountRoleMapper.selectList(new LambdaQueryWrapper<AccountRole>()
                .eq(AccountRole::getAccountId, userId)).stream().map(AccountRole::getRoleId).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(collect)) {
            loginAccountRespDTO.setRoles(RoleDTOTORoleEntity.INSTANCE.entity2dto(roleMapper.selectBatchIds(collect)));
            List<Long> menuIds = roleMenuMapper.selectList(new LambdaQueryWrapper<RoleMenu>()
                    .in(RoleMenu::getRoleId, collect)).stream().map(RoleMenu::getMenuId).collect(Collectors.toList());
            loginAccountRespDTO.setMenus(MenuUtils.treeMenu(menuMapper.selectList(new LambdaQueryWrapper<Menu>()
                    .in(Menu::getId, menuIds))));
        }
        return Resp.succeed(loginAccountRespDTO);
    }


}
